package 题目集.线段树or树状数组.树状数组;

import java.util.Arrays;
import java.util.Scanner;

/**
 * 思路：
 *  如果没有颜色限制，那么它是一个二维偏序问题。可以参考{@link ch05_二维偏序}
 *  对于 棍子i，我们先找出所有长度比它小的（一元），再从这些棍子中找出所有宽度比它大的（二元）。
 *  从这些棍子中找所有宽度比他大的可以用树状数组。
 *
 *  有颜色限制，我们可以额外开两个树状数组。
 *  每次查询都去其他两个树状数组中查
 */
public class ch07_拼十字 {
    static int maxV = (int) (1e5 + 10);
    static int[][] tree = new int[3][maxV];
    static int[][] src;
    static int n;
    static int mod = (int) (1e9 + 7);

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        src = new int[n][3];
        for (int[] s : src) {
            s[0] = sc.nextInt();
            s[1] = sc.nextInt();
            s[2] = sc.nextInt();
        }
        //因为是严格小于和严格大于，所以先按长升序，再按宽升序，这样如果有相同的长度，也是也不会加到宽度比自己大的（因为小的先加）
        Arrays.sort(src, (a, b) -> {
            if (a[0] == b[0]) {
                return a[1] - b[1];
            }
            return a[0] - b[0];
        });
        long res = 0;
        for (int[] v : src) {
            add(tree[v[2]], v[1], 1);
            for (int i = 0; i < tree.length; i++) {
                if (v[2] == i) continue;
                res += range(tree[i], v[1] + 1, maxV - 1);
            }
            res %= mod;
        }
        res %= mod;
        System.out.println(res);
    }

    public static void add(int[] tree, int i, int v) {
        while (i < maxV) {
            tree[i] += v;
            i += lowbit(i);
        }
    }

    public static long range(int[] tree, int l, int r) {
        return query(tree, r) - query(tree, l - 1);
    }

    public static long query(int[] tree, int i) {
        long res = 0;
        while (i > 0) {
            res += tree[i];
            i -= lowbit(i);
        }
        return res;
    }

    public static int lowbit(int x) {
        return x & -x;
    }
}
